package com.demo.service;

import com.demo.annotation.RedisLock;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

/**
 * @author chenyongjiu
 */
@Slf4j
@Service
public class RedisCacheService {

    /**
     * StringRedisTemplate 的默认序列化方式为 StringRedisSerializer
     */
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RedissonClient redissonClient;

    public void watchDog() {
        log.info("开始获取锁");
        RLock lock = redissonClient.getLock("watchDog");
        log.info("准备上锁");
        lock.lock();
        log.info("已上锁");
        lock.unlock();
    }

    public void tryLock() throws InterruptedException {
        RLock lock = redissonClient.getLock("watchDog");
        boolean flag = lock.tryLock(10, 100, TimeUnit.SECONDS);
        log.info("是否获取锁：{}", flag);
    }

    public void pipeLine() {
        int length = 10000;
        final StopWatch stopWatch = new StopWatch();
        stopWatch.start("foreach set");
        for (int i = 0; i < length; i++) {
            stringRedisTemplate.opsForSet().add("key1", String.valueOf(i));
        }
        stopWatch.stop();

        String[] array = new String[length];
        for (int i = 0; i < length; i++) {
            array[i] = String.valueOf(i);
        }

        stopWatch.start("mset");
        stringRedisTemplate.opsForSet().add("key2", array);
        stopWatch.stop();

        stopWatch.start("pipeline set");
        final byte[] key = "key3".getBytes(StandardCharsets.UTF_8);

        stringRedisTemplate.executePipelined((RedisCallback<?>) connection -> {
            for (int i = 0; i < length; i++) {
                connection.sAdd(key, String.valueOf(i).getBytes(StandardCharsets.UTF_8));
            }

            return null;
        });

        stopWatch.stop();
        log.info(stopWatch.prettyPrint());
    }

    @SneakyThrows
    @RedisLock(key = "#userId")
    public void redisLock(String userId, String name) {
        log.info("userId:{}， name:{}", userId, name);
        // 停留10秒，检查redis是否有数据
        Thread.sleep(10000L);
    }

    @SneakyThrows
    @RedisLock(key = "#userId", isWaitForLock = false)
    public void redisLockFail(Long userId) {
        log.info("userId:{}", userId);
        Thread.sleep(10000L);
    }
}
